﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Tycho.Runtime;
using System.Transactions;

namespace Tycho.Peyote {
    /// <summary>
    /// Interaction logic for StructureGlyph.xaml
    /// </summary>
    public partial class StructureGlyph : UserControl {
        AnyObject Structure;
        Environment Environment;

        public StructureGlyph (StructureObject structure, Environment environment) {
            InitializeComponent ();

            Structure = structure;
            Environment = environment;

            DataContext = this;

            PopulatePropertiesGrid ();
        }

        void PopulatePropertiesGrid () {
            var properties = GetProperties ();
            if (properties.Length == 0) {
                return;
            }

            int n = 0;

            GridSplitter splitter = new GridSplitter ();
            splitter.Width = 5;
            splitter.VerticalAlignment = VerticalAlignment.Stretch;
            splitter.HorizontalAlignment = HorizontalAlignment.Center;
            Grid.SetRowSpan (splitter, properties.Count ());
            Grid.SetColumn (splitter, 1);
            PropertiesGrid.Children.Add (splitter);

            foreach (PropertyValue prop in properties) {
                PropertiesGrid.RowDefinitions.Add (new RowDefinition ());

                UIElement name = Environment.Presenter.Present (prop.Name);
                Grid.SetColumn (name, 0);
                Grid.SetRow (name, n);
                PropertiesGrid.Children.Add (name);

                UIElement value = Environment.Presenter.Present (prop.Value);
                Grid.SetColumn (value, 2);
                Grid.SetRow (value, n);
                PropertiesGrid.Children.Add (value);

                n++;
            }
        }

        public PropertyValue [] GetProperties () {
            PropertyValue [] resultProps = null;

            Environment.Transaction (() => {
                var props = from prop in Structure.Properties
                            where NotRuntimeSymbol (prop)
                            select new PropertyValue { Name = prop, Value = Structure.GetProperty (prop) };
                // make sure the properties are retrieved within the transaction, not lazily later.
                resultProps = props.ToArray ();
            });

            return resultProps;
        }

        static bool NotRuntimeSymbol (AnyObject key) {
            Symbol symbol;
            
            if (key.TryCastTo(out symbol)) {
                return symbol.Namespace != Namespaces.Runtime;
            } else {
                return true;
            }
        }

        public class PropertyValue {
            public AnyObject Name { get; set; }
            public AnyObject Value { get; set; }
        }
    }

    class StructurePresenter : GlyphPresenter {
        public StructurePresenter () : base ("structure", new TypeSchemaObject<StructureObject> ()) { }

        public override UIElement Present (AnyObject obj, Environment environment) {
            return new StructureGlyph (obj.Expect<StructureObject> (), environment);
        }
    }
}
